﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: ModelValidationResultsHelper
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace VmroleAuthor.ViewModels
{
    public class ModelValidationResultsHelper
    {
        public static List<string> GetPropertyNames(Type propertiesClass)
        {
            FieldInfo[] fieldsToValidate = propertiesClass.GetFields();
            return fieldsToValidate.Select(fieldInfo => fieldInfo.Name).ToList();
        }

        private static void AddValidationErrorsForNonTreeChildViewModel(TreeViewItemViewModel parent, IDataErrorInfo dataErrorInfo)
        {
            Type type = dataErrorInfo.GetType();
            Type propertyNamesType = type.GetNestedType("PropertyNames");
            if (propertyNamesType == null)
            {
                if (type.BaseType != null)
                {
                    propertyNamesType = type.BaseType.GetNestedType("PropertyNames");
                }
            }
            if (propertyNamesType == null)
            {
                return;
            }
            List<string> propNames = GetPropertyNames(propertyNamesType);
            foreach (string propName in propNames)
            {
                string error = dataErrorInfo[propName];
                if (!string.IsNullOrEmpty(error))
                {
                    CloudServiceModelValidationResult cloudServiceModelValidationResult = new CloudServiceModelValidationResult
                    {
                        Message = string.Format("{0} : {1}", propName, error),
                        TreeViewItemViewModel = parent,
                        ValidationCategory = ValidationCategory.Error
                    };
                    ((IProduceValidationResults)parent).ValidationResults.Add(cloudServiceModelValidationResult);
                }
                else
                {
                    // Check Warnings
                    IDataWarningInfo dataWarningInfo = dataErrorInfo as IDataWarningInfo;
                    if (dataWarningInfo != null)
                    {
                        string warning = dataWarningInfo.GetWarning(propName);
                        if (!string.IsNullOrEmpty(warning))
                        {
                            CloudServiceModelValidationResult cloudServiceModelValidationResult = new CloudServiceModelValidationResult
                            {
                                Message = string.Format("{0} : {1}", propName, warning),
                                TreeViewItemViewModel = parent,
                                ValidationCategory = ValidationCategory.Warning
                            };
                            ((IProduceValidationResults)parent).ValidationResults.Add(cloudServiceModelValidationResult);
                        }
                    }

                    //Recursion, try this for errors
                    object propValue = type.GetProperty(propName).GetValue(dataErrorInfo);
                    AddValidationErrorsForNonTreeChildViewModels(parent, propValue);
                }
            }

        }

        private static void AddValidationErrorsForNonTreeChildViewModels(TreeViewItemViewModel parent, object childPropertyValue)
        {
            if ((childPropertyValue as TreeViewItemViewModel) != null)
            {
                return;
            }

            IDataErrorInfo dataErrorInfo = childPropertyValue as IDataErrorInfo;
            if (dataErrorInfo != null)
            {
                AddValidationErrorsForNonTreeChildViewModel(parent, dataErrorInfo);
            }
            else
            {
                IEnumerable<IDataErrorInfo> childNonTreeViewModels = childPropertyValue as IEnumerable<IDataErrorInfo>;
                if (childNonTreeViewModels != null)
                {
                    foreach (IDataErrorInfo childNonTreeViewModel in childNonTreeViewModels)
                    {
                        AddValidationErrorsForNonTreeChildViewModel(parent, childNonTreeViewModel);
                    }
                }
            }
        }


        public static void UpdateValidationResults(TreeViewItemViewModel parent, Type propertiesClass)
        {
            IProduceValidationResults parentProduceValidationResults = parent as IProduceValidationResults;
            if (parentProduceValidationResults == null)
            {
                return;
            }
            parentProduceValidationResults.ValidationResults.Clear();
            List<string> propNames = GetPropertyNames(propertiesClass);
            foreach (string propName in propNames)
            {
                string error = ((IDataErrorInfo)parent)[propName];
                if (!string.IsNullOrEmpty(error))
                {
                    CloudServiceModelValidationResult cloudServiceModelValidationResult = new CloudServiceModelValidationResult
                    {
                        Message = string.Format("{0} : {1}", propName, error),
                        TreeViewItemViewModel = parent,
                        ValidationCategory = ValidationCategory.Error
                    };
                    parentProduceValidationResults.ValidationResults.Add(cloudServiceModelValidationResult);                    
                }

                // Check Warnings
                IDataWarningInfo dataWarningInfo = parent as IDataWarningInfo;
                if (dataWarningInfo != null)
                {
                    string warning = dataWarningInfo.GetWarning(propName);
                    if (!string.IsNullOrEmpty(warning))
                    {
                        CloudServiceModelValidationResult cloudServiceModelValidationResult = new CloudServiceModelValidationResult
                        {
                            Message = string.Format("{0}", warning),
                            TreeViewItemViewModel = parent,
                            ValidationCategory = ValidationCategory.Warning
                        };
                        ((IProduceValidationResults)parent).ValidationResults.Add(cloudServiceModelValidationResult);
                    }
                }

                // Validate child properties
                object propValue = parent.GetType().GetProperty(propName).GetValue(parent);
                AddValidationErrorsForNonTreeChildViewModels(parent, propValue);
            }

            foreach (TreeViewItemViewModel child in parent.Children)
            {
                IProduceValidationResults childProduceValidationResults = child as IProduceValidationResults;
                if (childProduceValidationResults != null)
                {
                    childProduceValidationResults.UpdateValidationResults();
                    foreach (CloudServiceModelValidationResult result in childProduceValidationResults.ValidationResults)
                    {
                        parentProduceValidationResults.ValidationResults.Add(result);
                    }
                }
            }
        }

    }
}
